#ifndef __QTCH_SCHEDULER_H__
#define __QTCH_SCHEDULER_H__



#include"fiber.h"
#include<memory>
#include<string>
#include<vector>
#include<pthread.h>
#include<atomic>
#include<list>
#include"mutex.h"
#include"thread.h"
#include"log.h"


namespace qtch{


class Scheduler {
public:
    typedef std::shared_ptr<Scheduler> ptr;
    typedef Mutex MutexType;

    Scheduler(size_t threads = 1,bool use_caller = true,const std::string& name ="");
    ~Scheduler();
    void start();
    void run();
    void stop();
    static Scheduler* getThis();
    const std::string getName() const{return m_name;}
    static Fiber::ptr GetMainFiber();

    size_t getActiveThreadCount() const { return m_activeThreadCount.load();}
    size_t getIdleThreadCount() const { return m_idleThreadCount.load();}
    bool hasIdleThreads() const { return m_idleThreadCount > 0;}

    template<class FiberOrCb>
    void schedule(FiberOrCb fc,int thread = -1){
        bool needTickle = false;
        {
            MutexType::Lock lock(m_mutex);
            needTickle = scheduleNoLock(fc,thread);
        }
        if(needTickle){
            tickle();
        }
    }
    
    template<class InputIterator>
    void schedule(InputIterator begin, InputIterator end){
        if(m_autoStop){
            return;
        }
        bool needTickle = false;
        {
            MutexType::Lock lock(m_mutex);
            while(begin != end){
                needTickle |= scheduleNoLock((*begin),-1);
                ++begin;
            }
        }
        if(needTickle){
            tickle();
        }
    }

    template<class FiberOrCb>
    bool scheduleNoLock(FiberOrCb fc,int thread = -1){
        if(m_autoStop){
            return false;
        }
        bool needTickle = m_fibers.empty();
        FiberAndThread f(fc,thread);
        if(f.fiber||f.cb){
            m_fibers.push_back(f);
        }
        return needTickle;
    }

    std::ostream& dump(std::ostream& os);


protected:
    virtual bool stopping();
    virtual void tickle();
    virtual void idle();
    void setThis();


private:


    class FiberAndThread{
    public:
        FiberAndThread(Fiber::ptr f,int thr  = -1)
            :fiber(f),threadId(thr){
        }
        FiberAndThread(std::function<void()> f, int thr = -1)
            :cb(f),threadId(thr){
        }
        FiberAndThread(){
            threadId = -1;
        }
        void reset(){
            fiber.reset();
            cb = nullptr;
            threadId = -1;
        }

        Fiber::ptr fiber = nullptr;
        std::function<void()> cb = nullptr;
        int threadId;
    };

    // 调度器名称
    std::string m_name;

    // 线程池
    std::vector<qtch::Thread::ptr> m_threads;

    // 待执行的协程队列
    std::list<FiberAndThread> m_fibers;

    // mutex
    MutexType m_mutex;

    // use_caller 为true时有效
    bool m_userCaller;



protected:

    // 调度器下的线程id数组
    std::vector<int> m_threadIds;
    // 工作线程数量
    std::atomic<size_t> m_activeThreadCount = {0};
    // 空闲线程数量
    std::atomic<size_t> m_idleThreadCount ={0};
    // 总线程数量
    size_t m_threadCount = 0;
    // 主线程id(use_caller)
    int m_rootThread = 0;
    // 是否正在停止
    bool m_stopping = true;
    // 是否自动停止
    bool m_autoStop = false;


};

}


#endif